﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel.Composition;
using System.IO;

namespace Steve
{
    public abstract class ContentAdministrationRepository : AuditRepositoryBase
    {
        const string LogCategory = "Steve-ContentAdministrationRepository";

        [Import]
        public ISearchIndexService Index { get; set; }
        [Import]
        public ICacheService Cache { get; set; }
        [Import]
        public CategoryRepository CategoryRepository { get; set; }

        public Guid NewContentData(Stream data)
        {
            if (data == null) throw new ArgumentNullException("data");

            var id = Guid.NewGuid();

            NewContentDataCore(id, CurrentRevisionDate, data);

            return id;
        }

        protected abstract void ApproveContentCore(Guid contentId, int revisionNumber);

        public void ApproveContent(Guid contentId, int revisionNumber)
        {
            ApproveContentCore(contentId, revisionNumber);

            //reindex
            Index.Index(new Tuple<Guid, int>[] { Tuple.Create(contentId, revisionNumber) });
        }

        public Content SaveContentAndCategories(Content toSave, IEnumerable<string> categories)
        {
            if (toSave == null) throw new ArgumentNullException("toSave");

            //TODO: transaction around both saves?
            ProcessAudit(toSave);
            var returnValue = SaveContentCore(toSave);

            SaveContentCategories(toSave.Id, categories);

            Cache.Invalidate(CacheType.ContentDirectory);

            //reindex
            Index.Index(new Tuple<Guid, int>[] { Tuple.Create(toSave.Id, toSave.LatestRevisionNumber) });

            return returnValue;
        }

        //TODO: when we support end user tagging, should this still exist in this repository? possible security hole?
        protected abstract void SaveContentCategoriesCore(Guid contentId, IEnumerable<string> categories, DateTime revisionDate, Guid? revisionMembershipId);
        protected abstract Content SaveContentCore(Content toSave);
        protected abstract void NewContentDataCore(Guid id, DateTime createDate, Stream data);

        public virtual void SaveContentCategories(Guid contentId, IEnumerable<string> categories)
        {
            SaveContentCategoriesCore(contentId, categories, CurrentRevisionDate, CurrentAuthenticatedMembershipId);
            RebuildContentSimilarityCache(contentId);
        }

        public void RebuildContentSimilarityCache()
        {
            RebuildContentSimilarityCache(null);
        }

        //TODO: take this async and make it an incremental cache build?
        public abstract void RebuildContentSimilarityCache(Guid? updatedId);

        //TODO: move this stuff to user specific repository or something?
        protected abstract void MarkContentReadCore(Guid contentId, DateTime readDate, decimal? rating, Guid membershipId);

        public void MarkContentRead(Guid contentId, decimal? rating)
        {
            //mark read even if not authenticated
            var user = Account.GetUser();

            if (user == null) return;

            var membershipId = (Guid)user.ProviderUserKey;

            MarkContentReadCore(contentId, CurrentRevisionDate, rating, membershipId);
        }

        
        
    }
}
